﻿using System;
using System.Collections;
using System.Reflection;
using System.Web;
using System.Web.Caching;
using System.Web.Hosting;
using TemplateFoundation.Reflection;

namespace TemplateFoundation.Gadgets
{
    /// <summary>
    /// Used to provide access to embedded resources as files
    /// </summary>
    public class GadgetVirtualPathProvider : VirtualPathProvider
    {
        private AssemblyHelper _assemblyHelper;

        #region Constructors
        
        public GadgetVirtualPathProvider(string prefix, Assembly assembly)
        {
            if (prefix.StartsWith("~"))
            {
                prefix = prefix.Substring(1);
            }

            if (!prefix.StartsWith("/"))
            {
                prefix = string.Concat("/", prefix);
            }

            VppPathPrefix = VirtualPathUtility.AppendTrailingSlash(prefix);

            _assemblyHelper = new AssemblyHelper(assembly);
        }

        #endregion

        #region Private members

        private bool IsAppResourcePath(string virtualPath)
        {
            var checkPath = VirtualPathUtility.ToAppRelative(virtualPath);

            var validPath = checkPath.StartsWith(string.Concat("~", VppPathPrefix), StringComparison.InvariantCultureIgnoreCase);

            if (!validPath) // Not below the VPP path prefix
            {
                return false;
            }

            var file = new GadgetResourceVirtualFile(RemoveVppPrefix(virtualPath), _assemblyHelper.Assembly);

            return file.FileExists;
        }

        #endregion

        #region Public members
        
        /// <summary>
        /// Checks if the virtual path is for a valid existing file
        /// </summary>
        /// <param name="virtualPath">A virtual path, for example: /Content/Images/MyImage.jpg</param>
        /// <returns>True if the file exists</returns>
        public override bool FileExists(string virtualPath)
        {
            return IsAppResourcePath(virtualPath) || base.FileExists(virtualPath);
        }

        /// <summary>
        /// Gets a file based on its virtual path
        /// </summary>
        /// <param name="virtualPath">A virtual path, for example: /Content/Images/MyImage.jpg</param>
        /// <returns>A virtual file</returns>
        public override VirtualFile GetFile(string virtualPath)
        {
            return IsAppResourcePath(virtualPath) 
                   ? new GadgetResourceVirtualFile(RemoveVppPrefix(virtualPath), _assemblyHelper.Assembly) 
                   : base.GetFile(virtualPath);
        }

        /// <summary>
        /// Gets a cache dependency object for a specific file
        /// </summary>
        /// <param name="virtualPath"></param>
        /// <param name="virtualPathDependencies"></param>
        /// <param name="utcStart"></param>
        /// <returns></returns>
        public override CacheDependency GetCacheDependency(string virtualPath, IEnumerable virtualPathDependencies, DateTime utcStart)
        {
            return IsAppResourcePath(virtualPath) 
                   ? null 
                   : base.GetCacheDependency(virtualPath, virtualPathDependencies, utcStart);
        }

        /// <summary>
        /// Gets the VPP path prefix
        /// </summary>
        public static string VppPathPrefix { get; protected set;}

        public static string RemoveVppPrefix(string virtualPath)
        {
            var pathWithoutPrefix = virtualPath.Replace(VppPathPrefix, string.Empty);

            if (!pathWithoutPrefix.StartsWith("/"))
            {
                pathWithoutPrefix = string.Concat("/", pathWithoutPrefix);
            }

            return pathWithoutPrefix;
        }

        ///// <summary>
        ///// Takes a virtual path and removes any leading prefix
        ///// </summary>
        ///// <param name="virtualPath">A virtual path, for example: /VPP/Prefix/MyFolder/MyImage</param>
        ///// <returns>An app-relative path, for example: ~/MyAssembly.MyNamespaceMyFolder/MyImage</returns>
        ///// <remarks>The VPP path prefix is set by the constructor and available through the VppPathPrefix property</remarks>
        //public static string GetAppRelativePath(string virtualPath)
        //{
        //    if (!virtualPath.StartsWith("/") && !virtualPath.StartsWith("~/"))
        //    {
        //        virtualPath = string.Concat("/", virtualPath);
        //    }

        //    if (virtualPath.StartsWith("~"))
        //    {
        //        virtualPath = virtualPath.Substring(1);
        //    }

        //    return VirtualPathUtility.ToAppRelative(virtualPath).Replace(VppPathPrefix, string.Empty);
        //}

        #endregion
    }
}